home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Converters / Convert_MacPaint / Source / shared.subproj / RCS / File.m,v < prev    next >
Text File  |  1995-06-12  |  75KB  |  2,377 lines

  1. head     1.8;
  2. branch   ;
  3. access   ;
  4. symbols  beta10:1.7;
  5. locks    death:1.8; strict;
  6. comment  @@;
  7.  
  8.  
  9. 1.8
  10. date     93.04.04.23.44.26;  author death;  state Exp;
  11. branches ;
  12. next     1.7;
  13.  
  14. 1.7
  15. date     93.01.10.15.07.54;  author death;  state Exp;
  16. branches ;
  17. next     1.6;
  18.  
  19. 1.6
  20. date     92.07.26.13.58.06;  author death;  state Exp;
  21. branches ;
  22. next     1.5;
  23.  
  24. 1.5
  25. date     92.04.27.20.40.36;  author death;  state Exp;
  26. branches ;
  27. next     1.4;
  28.  
  29. 1.4
  30. date     92.04.05.22.51.36;  author death;  state Exp;
  31. branches ;
  32. next     1.3;
  33.  
  34. 1.3
  35. date     92.03.29.12.36.14;  author death;  state Exp;
  36. branches ;
  37. next     1.2;
  38.  
  39. 1.2
  40. date     92.03.29.12.29.06;  author death;  state Exp;
  41. branches ;
  42. next     1.1;
  43.  
  44. 1.1
  45. date     92.03.29.12.18.44;  author death;  state Exp;
  46. branches ;
  47. next     ;
  48.  
  49.  
  50. desc
  51. @This is the implementation of the early draft of the file object.
  52. @
  53.  
  54.  
  55. 1.8
  56. log
  57. @Sun Apr  4 23:44:26 PDT 1993
  58. @
  59. text
  60. @/*
  61. ====================================================================
  62. This is the implementation file for the File class.  Full documentation for this class can be found in the File.rtf file.  I will not duplicate all that fine information here.
  63.     This is $Revision: 1.7 $ of this file
  64.     It was last modified by $Author: death $ on $Date: 93/01/10 15:07:54 $
  65. Note that this file was created while using the New Century Schoolbook Roman typeface.  You may find that some things line up strangely if you don't use that family.
  66.  * $Log:    File.m,v $
  67. Revision 1.7  93/01/10  15:07:54  death
  68. Sun Jan 10 15:07:54 PST 1993
  69.  
  70. Revision 1.6  92/07/26  13:58:06  death
  71. Update so all works with the font converter...
  72.  
  73.  
  74. Revision 1.4  92/04/05  22:51:36  death
  75. Miscelaneous revisions.  This is the last version of version 1.
  76.  
  77. Revision 1.3  92/03/29  12:36:14  death
  78. Bug in the open method. If we failed, we returned OK, if we succed, we reported failure.
  79.  
  80. Revision 1.2  92/03/29  12:29:06  death
  81. Oops.  Managed to check in the wrong version.  this one has the code reflecting the new location of the init methods 
  82.  
  83. Revision 1.1  92/03/29  12:18:44  death
  84. Initial revision
  85.  
  86.  *====================================================================
  87. */
  88.  
  89. //
  90. //    Import our own definition
  91. //
  92. #import "File.h"
  93.  
  94. #import <stdio.h>    
  95. #import <string.h>
  96. #import <stdlib.h>
  97. #import <sys/param.h>    // for maxpathlen
  98. #import <libc.h>            // for getwd
  99. #import <sys/file.h>        // for open()
  100. #import    <streams/streams.h>    // for streams stuff (exception codes)
  101. #include <sys/time.h>        // for gettimeofday
  102. #if (NSmajor == 3)
  103. #    import    <errno.h>
  104. #endif
  105.  
  106. @@implementation File
  107.  
  108. //
  109. //    @@@@@@ bugs... doesn't deal with links properly.  =(
  110. //
  111.  
  112. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  113. //    Routine:        CreateAndOpenFor
  114. //    Parameters:    the means of accessing the specified file
  115. //    Returns:        self
  116. //    Stores:        none
  117. //    Description:
  118. //        This method will try to create a new file and open it.  The file is presumed
  119. //        to be the one whose path is stored in the instance variables of this object.
  120. //        If the file already exists, or if an error occurrs when trying to creat it,
  121. //        an error is stored.  Otherwise the file is opened, and the object is ready for use.
  122. //    Bugs:
  123. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  124. - CreateAndOpenFor: (AccessType) access
  125. {
  126.     //
  127.     //    If the object is working with a file already give an error.
  128.     //    otherwise, do our stuff.
  129.     //
  130.     if (TheFile != NULL)
  131.         [self StoreErrorCode: ERR_SOMEFILEOPEN
  132.             AndText: "Object already in use for another file."];
  133.     {
  134.         if ([self FileExists: FileName] == YES)
  135.             [self StoreErrorCode: ERR_FILEEXISTS
  136.                 AndText: "Can't create the requested file. It already exists."];
  137.         else
  138.         {
  139.             [self CreateFile: FileName];
  140.             if ([self GetErrorCode] != ERR_OK)
  141.                 [self StoreErrorCode: ERR_CREATEFAIL
  142.                     AndText: "Can't create the requested file."];
  143.             else
  144.                 [self OpenWithAccess: access];
  145.                 // Error info stored by this method.
  146.         }
  147.     }
  148.     return self;
  149. }
  150.  
  151. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. //    Routine:        OpenExistingFor
  153. //    Parameters:    the means of accessing the specified file
  154. //    Returns:        self
  155. //    Stores:        none
  156. //    Description:
  157. //        This method will try to open an existing file.  The file is presumed
  158. //        to be the one whose path is stored in the instance variables of this object.
  159. //        If the file does not exist,  an error is stored. Otherwise the file is opened,
  160. //        and the object is ready for use.
  161. //    Bugs:
  162. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. - OpenExistingFor: (AccessType) access
  164. {
  165.     //
  166.     //    If the object is working with a file already give an error.
  167.     //    otherwise, do our stuff.
  168.     //
  169.     if (TheFile != NULL)
  170.         [self StoreErrorCode: ERR_SOMEFILEOPEN
  171.             AndText: "Object already in use for another file."];
  172.     {
  173.          if ([self FileExists: FileName] == NO)
  174.             [self StoreErrorCode: ERR_FILEDOESNTEXIST
  175.                 AndText: "Can't locate the requested file."];
  176.         else
  177.             [self OpenWithAccess: access];
  178.             // Error info stored by this method.
  179.     }
  180.     return self;
  181. }
  182.  
  183.  
  184. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  185. //    Routine:        ClearAndOpenExistingFor
  186. //    Parameters:    the means of accessing the specified file
  187. //    Returns:        self
  188. //    Stores:        none
  189. //    Description:
  190. //        This method will try to open an existing fil, and then clear (truncate) it.
  191. //        The file is presumed to be the one whose path is stored in the instance
  192. //        variables of this object. If the file does not exist, or if an error occurrs while
  193. //        clearing it,  an error is stored. Otherwise the file is opened,
  194. //        and the object is ready for use.
  195. //    Bugs:
  196. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  197. - ClearAndOpenExistingFor: (AccessType) access
  198. {
  199.     //
  200.     //    If the object is working with a file already give an error.
  201.     //    otherwise, do our stuff.
  202.     //
  203.     if (TheFile != NULL)
  204.         [self StoreErrorCode: ERR_SOMEFILEOPEN
  205.             AndText: "Object already in use for another file."];
  206.     {
  207.          if ([self FileExists: FileName] == NO)
  208.             [self StoreErrorCode: ERR_FILEDOESNTEXIST
  209.                 AndText: "Can't locate the requested file."];
  210.         else
  211.         {
  212.             [self ClearFile: FileName];
  213.             if ([self GetErrorCode] != ERR_OK)
  214.                 [self StoreErrorCode: ERR_CLEARFAIL
  215.                     AndText: "Can't clear the file!"];
  216.             else
  217.                 [self OpenWithAccess: access];
  218.                 // Error info stored by this method.
  219.         }
  220.     }
  221.     return self;
  222. }
  223.  
  224.  
  225. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. //    Routine:        ClearAndOpenFor
  227. //    Parameters:    the means of accessing the specified file
  228. //    Returns:        self
  229. //    Stores:        none
  230. //    Description:
  231. //        This method will try to open a file.  If it doesn't exist already, it will create it.
  232. //        if it does, then it will clear it (truncate).  The file is then opened if all went well
  233. //        The file is presumed to be the one whose path is stored in the instance
  234. //        variables of this object. 
  235. //    Bugs:
  236. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. - ClearAndOpenFor: (AccessType) access
  238. {
  239.     //
  240.     //    If the object is working with a file already give an error.
  241.     //    otherwise, do our stuff.
  242.     //
  243.     if (TheFile != NULL)
  244.         [self StoreErrorCode: ERR_SOMEFILEOPEN
  245.             AndText: "Object already in use for another file."];
  246.     {
  247.          if ([self FileExists: FileName] == NO)
  248.         {
  249.             [self CreateFile: FileName];
  250.             if ([self GetErrorCode] != ERR_OK)
  251.                 [self StoreErrorCode: ERR_CREATEFAIL
  252.                     AndText: "Can't create the requested file."];
  253.         }
  254.         else
  255.         {
  256.             [self ClearFile: FileName];
  257.             if ([self GetErrorCode] != ERR_OK)
  258.                 [self StoreErrorCode: ERR_CLEARFAIL
  259.                     AndText: "Can't clear the file!"];
  260.         }
  261.         //
  262.         //    The file exists and is of 0 length.  open it now.
  263.         //
  264.         if ([self GetErrorCode] == ERR_OK)
  265.             [self OpenWithAccess: access];
  266.     }
  267.     return self;
  268. }
  269.  
  270.  
  271. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. //    Routine:        OpenFor
  273. //    Parameters:    the means of accessing the specified file
  274. //    Returns:        self
  275. //    Stores:        none
  276. //    Description:
  277. //        This method will try to open a file.  If it doesn't exist already, it will create it.
  278. //        The file is then opened if all went well.
  279. //        The file is presumed to be the one whose path is stored in the instance
  280. //        variables of this object. 
  281. //    Bugs:
  282. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. - OpenFor: (AccessType) access
  284. {
  285.     //
  286.     //    If the object is working with a file already give an error.
  287.     //    otherwise, do our stuff.
  288.     //
  289.     if (TheFile != NULL)
  290.         [self StoreErrorCode: ERR_SOMEFILEOPEN
  291.             AndText: "Object already in use for another file."];
  292.     {
  293.          if ([self FileExists: FileName] == NO)
  294.         {
  295.             [self CreateFile: FileName];
  296.             if ([self GetErrorCode] != ERR_OK)
  297.                 [self StoreErrorCode: ERR_CREATEFAIL
  298.                     AndText: "Can't create the requested file."];
  299.         }
  300.         else
  301.                 [self StoreErrorCode: ERR_OK  AndText: "File exists.  all is peachy."];
  302.         //
  303.         //    The file exists.  open it now.
  304.         //
  305.         if ([self GetErrorCode] == ERR_OK)
  306.             [self OpenWithAccess: access];
  307.     }
  308.     return self;
  309. }
  310.  
  311.  
  312.  
  313. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. //    Routine:        OpenWithAccess:
  315. //    Parameters:    the means of accessing the specified file
  316. //    Returns:        self
  317. //    Stores:        none
  318. //    Description:
  319. //        This is a lower level opening routine.  It should probably never be called from
  320. //        the outside, but instead be called by the (presently) five opening routines
  321. //        above this in the listing.
  322. //        It's purpose is simple: open the file that this object is going to work with.
  323. //        If the file does'nt exist, it returns an error.  Thus, it is up to the caller to
  324. //        assure that the file exists and is in th proper form before calling this.
  325. //    Bugs:
  326. //    Not accounting for the fact that I may not have *permission* (666 kinda thing)
  327. //    to do any of these...
  328. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  329. - OpenWithAccess: (AccessType) operation
  330. {
  331.     struct stat *statBuf;
  332.     [self ResetResults];
  333.     
  334.     //
  335.     //    Make sure that the file exists, and that we aren't already working with
  336.     //    an opened file.  If all is good, open it appropriately
  337.     //
  338.     if (([self FileExists: FileName] == YES) && (TheFile == NULL))
  339.     {
  340.         switch (operation)
  341.         {
  342.             case FILE_READ:
  343.                 TheFile = NXMapFile(FileName, NX_READONLY);
  344.                 break;
  345.             case FILE_WRITE:
  346.                 TheFile = NXMapFile(FileName, NX_WRITEONLY);
  347.                 break;
  348.             case    FILE_READWRITE:
  349.                 TheFile = NXMapFile(FileName, NX_READWRITE);
  350.                 break;
  351.             case FILE_APPEND:
  352.                 TheFile = NXMapFile(FileName, NX_WRITEONLY);
  353.                 //
  354.                 //    Appending must be at the end of the file...
  355.                 //    @@@@@@ do we need + 1 here?
  356.                 //
  357.                 [self MoveTo: [self FileSize]];
  358.                 break;
  359.             default:
  360.                 [self StoreErrorCode: ERR_BADACCESS
  361.                     AndText: "An invalid access operation was requested. No file opened."];
  362.                 break;
  363.         }
  364.     }
  365.     //
  366.     //    If the file wasn't opened, or some other problem arose, generate a negative reply.
  367.     //
  368.     if ((TheFile == NULL) && ([self GetErrorCode] != ERR_BADACCESS))
  369.         [self StoreErrorCode: ERR_CANTOPEN
  370.                 AndText: "The specified file could not be opened (bad permissions?  Bad path?)"];
  371.     else
  372.     {
  373.         AccessMode = operation;
  374.         //
  375.         //    Store the real inode now, in case we could not get it during the init.
  376.         //
  377.         [self    FileInfo];
  378.         if ([self GetErrorCode] != ERR_OK)
  379.             TheInode = 0;
  380.         else
  381.         {
  382.             statBuf = (struct stat *) [self GetPointerFrom: SECOND_RESULT];
  383.             TheInode = statBuf->st_ino;
  384.         }
  385.     }
  386.     //
  387.     //    Store whether the file was opened or not
  388.     //
  389.     if ((TheFile != NULL) && ([self GetErrorCode] == ERR_OK))
  390.     {
  391.         FileIsOpen = YES;
  392.         FileLocation = fileAtStart;
  393.     }
  394.  
  395.     return self;
  396. }
  397.  
  398.  
  399. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  400. //    Routine:        initAndUse:
  401. //    Parameters:    none
  402. //    Returns:        self
  403. //    Stores:        none
  404. //    Description:
  405. //        This funky method is a pretty standard init method.  It sets up all our instance
  406. //        variables, and does nothing more.
  407. //    Bugs:
  408. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  409. - initAndUse: (roCString) pathname
  410. {
  411.     struct stat *statbuf;
  412.     
  413.     [super init];
  414.     FileName = [self GetFullPathFrom: pathname];
  415.     AccessMode = FILE_NOACCESS;
  416.     TheFile = NULL;
  417.     //
  418.     //    Get our inode, if possible.
  419.     //
  420.     [self    FileInfo];
  421.     if ([self GetErrorCode] != ERR_OK)
  422.     {
  423.         //  @@@@@@ Maybe this shouldn't be this way...
  424.         [self   StoreErrorCode: ERR_OK  AndText: "Hmmmmmm"];
  425.         TheInode = 0;
  426.     }
  427.     else
  428.     {
  429.         statbuf = (struct stat *) [self GetPointerFrom: SECOND_RESULT];
  430.         TheInode = statbuf->st_ino;
  431.     }
  432.  
  433.     FileIsOpen = NO;
  434.     FileLocation = fileAtStart;
  435.  
  436.     return self;
  437. }
  438.  
  439.  
  440. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  441. //    Routine:        initAndUseTemporary
  442. //    Parameters:    none
  443. //    Returns:        self
  444. //    Stores:        none
  445. //    Description:
  446. //        This method is used when one wishes to have a temporary file to use.
  447. //        Calling this method will cause a temporary file to be created somwhere.
  448. //        one can then use it as a completely ordinary file with this object.
  449. //    Bugs:
  450. //        At the moment, this is implemented with the tmpname call.  Because we
  451. //        ignore the TMP_MAX constant (the object shouldn't be tracking how many
  452. //        temp files are open in the program, and the program shouldn't know we're
  453. //        making use of tmpnam), we run the risk of opening too many temp files.
  454. //        Thus, this should be re-implemented ourselves sometime (perhaps to:
  455. //        /tmp/FileObj_TempXXXXXXXX, where X is a number-thing that will actually
  456. //        be a date from a date object, or some something more unique...
  457. //    History
  458. //        93.01.03    djb    Added call to stat, because it seems you have to call tmpnam repeatedly
  459. //                    to get your unique name.  YICK!  Please move to the above.  Then
  460. //                    replaced with intermediate hack using a pretty unique name using the
  461. //                    above and the process id, seconds since 1970, and microseconds.
  462. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. - initAndUseTemporary
  464. {
  465.     struct timeval tp;
  466.     struct timezone tzp;
  467.     [super init];
  468.  
  469.     FileName = NewCString(63);
  470.     gettimeofday(&tp, &tzp);
  471.     //    93.01.24    djb    Added the 'long' designation to the %d's at the NS3 compiler's suggestion.
  472.     sprintf(FileName, "/tmp/TempFileDataP%dS%ldU%ld",
  473.         getpid(), tp.tv_sec, tp.tv_usec);
  474.  
  475. /*
  476.     This approach does not work.  Nor do previsu simpler ones.
  477.     FileName = NewCString(L_tmpnam);
  478.     ctr = 0;
  479.     do
  480.     {
  481.         FileName = tmpnam(FileName);
  482.         result = stat(FileName, &mystat);
  483.         ctr++;
  484.     }
  485.     while ((errno != 2) && (ctr < TMP_MAX));
  486. */
  487.  
  488.     AccessMode = FILE_NOACCESS;
  489.     TheFile = NULL;
  490.     FileIsOpen = NO;
  491.     FileLocation = fileAtStart;
  492.     return self;
  493. }
  494.  
  495.  
  496. //============================================================
  497. //============================================================
  498.  
  499.  
  500. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  501. //    Routine:        ClearFile:
  502. //    Parameters:    a CString that contains a path to a file
  503. //    Returns:        self
  504. //    Stores:        none
  505. //    Description:
  506. //        This little kludgey method just clears the specified file.  If anything bad
  507. //        happens, it stores an error code and text.  At the moment, it truncates the file
  508. //        by opening it with the O_TRUNC flag to the open() routine.  yech.  This
  509. //        implementation had BETTER remain transparent to this and all subclasses,
  510. //        for it's sure to change at some point!
  511. //    Bugs:
  512. //        Ickly implementation.
  513. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  514. - ClearFile: (CString) pathname
  515. {
  516.     int fd;
  517.     
  518.     errno = 0;
  519.     fd =open(pathname, O_RDONLY|O_TRUNC, 666);
  520.     if (errno != 0)
  521.         [self StoreErrorCode: ERR_CLEARFAIL AndText: "The open() routine didn't O_TRUNC it!"];
  522.     close (fd);
  523.     return self;
  524. }
  525.  
  526.  
  527. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. //    Routine:        CreateFile:
  529. //    Parameters:    a CString that contains a path to a file
  530. //    Returns:        self
  531. //    Stores:        none
  532. //    Description:
  533. //        This little kludgey method just creates the specified file.  If anything bad
  534. //        happens, it stores an error code and text.  At the moment, it creates the file
  535. //        by opening it with the O_CREAT flag to the open() routine.  yech.  This
  536. //        implementation had BETTER remain transparent to this and all subclasses,
  537. //        for it's sure to change at some point!
  538. //    Bugs:
  539. //        Ickly implementation.
  540. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  541. - CreateFile: (CString) pathname
  542. {
  543.     int fd;
  544.     
  545.     errno = 0;
  546.     fd =open(pathname, O_RDONLY|O_CREAT, 0666);
  547.     if (errno != 0)
  548.         [self StoreErrorCode: ERR_CREATEFAIL AndText: "The open() routine didn't create it!"];
  549.     else
  550.         [self StoreErrorCode: ERR_OK AndText: "The file was created"];
  551.     close (fd);
  552.     return self;
  553. }
  554.  
  555.  
  556. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  557. //    Routine:        FileExists: 
  558. //    Parameters:    a CString that contains a path to a file
  559. //    Returns:        True if the file exists
  560. //    Stores:        the return value
  561. //    Description:
  562. //        This method has only one purpose: it returns YES if the specified file
  563. //        exists, and NO otherwise.  It does this in a kludgey kinda fashion.  Try to
  564. //        open the file (read only).  if we don't get an error, it must exist.  otherwise,
  565. //        it must not exist.  close the file, and return the value.
  566. //    Bugs:
  567. //        There's got to be a better way...
  568. //        Also, we always return an ERR_OK value...  certianly *something* can go wrong?
  569. //        Probably should be using stat???
  570. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  571. - (Boolean) FileExists: (CString) pathname
  572. {
  573.     int fd;
  574.     Integer temp;
  575.     
  576.     errno = 0;
  577.     fd = open(pathname, O_RDONLY, 666);
  578.     temp = errno;
  579.     close (fd);
  580.     if (temp != 0)
  581.     {
  582.         [self StoreErrorCode: ERR_OK AndText: "The file does not exist"];
  583.         return NO;
  584.     }
  585.     else
  586.     {
  587.         [self StoreErrorCode: ERR_OK AndText: "The file does indeed exist"];
  588.         return YES;
  589.     }
  590. }
  591.  
  592.  
  593. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  594. //    Routine:        GetFullPathFrom
  595. //    Parameters:    a CString that contains a full or partial path to a file
  596. //    Returns:        a new CString containing the full path to the file
  597. //    Stores:        the new CString
  598. //    Description:
  599. //        The purpose of this string is to take a full or partial pathname (i.e.
  600. //        /me/Library/file.ext  or Library/file.ext or file.ext), and return the full
  601. //        pathname to the file.
  602. //        If we were passed a full pathname (starts with the / character), then we
  603. //        make a full copy of it.
  604. //        otherwise, use the function getwd to get the path to the current directory,
  605. //        and fuse the two together.
  606. //        Note that we do not reset the results here.  Since this is an internal
  607. //        method, the caller, in the object, may not want things cleared.
  608. //    Bugs:
  609. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  610. - (CString) GetFullPathFrom: (roCString) pathname
  611. {
  612.     char    rootedpath[MAXPATHLEN];
  613.     CString    fullpath;
  614.     char*    pathresult;
  615.  
  616.     //
  617.     //    If the path is a complete path, then just copy it literally.
  618.     //
  619.     if (pathname[0] == '/')
  620.     {
  621.         fullpath = (CString) malloc(strlen(pathname) + 1);
  622.         strcpy(fullpath, pathname);
  623.         [self StoreErrorCode: ERR_OK AndText: "Got filename!"];
  624.     }
  625.     else
  626.     {
  627.         //
  628.         //    Otherwise, we have a partial path.  Get path to our current location
  629.         //    (presumably where the partial path starts from), and fuse the two
  630.         //    (if getwd() returns an error, something is wrong, and so we risk returning
  631.         //    just the partial path)
  632.         //
  633.          pathresult = getwd(rootedpath);
  634.         if (*pathresult != 0)
  635.         {
  636.             fullpath = (CString) malloc(strlen(rootedpath)+1+strlen(pathname) + 1);
  637.             sprintf(fullpath, "%s/%s", rootedpath, pathname);
  638.             [self StoreErrorCode: ERR_OK AndText: "Got filename!"];
  639.         }
  640.         else
  641.         {
  642.             fullpath = (CString) malloc(strlen(pathname) + 1);
  643.             strcpy(fullpath, pathname);
  644.             [self StoreErrorCode: ERR_STRANGEPATH AndText: "Pathname may be corrupted!"];
  645.         }
  646.     }
  647.     return fullpath;
  648. }
  649.  
  650. //============================================================
  651. //============================================================
  652.  
  653.  
  654. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  655. //    Routine:        Close
  656. //    Parameters:    a flag to indicate whether we should save the file
  657. //    Returns:        self
  658. //    Stores:        none
  659. //    Description:
  660. //        This closes the file, discarding any changes.
  661. //    Bugs:
  662. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  663. - Close
  664. {
  665.     [self ResetResults];
  666.  
  667.     if (TheFile != NULL)
  668.     {
  669.         NXCloseMemory(TheFile, NX_FREEBUFFER);
  670.         [self StoreErrorCode: ERR_OK AndText: "Closed right up"];
  671.     }
  672.     else
  673.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "No file open to close!"];
  674.  
  675.     FileIsOpen = NO;
  676.     FileLocation = fileAtStart;
  677.  
  678.     return self;
  679. }
  680.  
  681.  
  682. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  683. //    Routine:        CloseAndSave
  684. //    Parameters:    none
  685. //    Returns:        self
  686. //    Stores:        none
  687. //    Description:
  688. //        This closes the file,saving its contents before doing so.
  689. //    Bugs:
  690. //        how about some checking to make sure we dumped it all OK??
  691. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  692. - CloseAndSave
  693. {
  694.     [self ResetResults];
  695.  
  696.     if (TheFile != NULL)
  697.     {
  698.         if (AccessMode != FILE_READ)
  699.             NXSaveToFile(TheFile, FileName);
  700.         NXCloseMemory(TheFile, NX_FREEBUFFER);
  701.         [self StoreErrorCode: ERR_OK AndText: "Closed right up"];
  702.     }
  703.     else
  704.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "No file open to close!"];
  705.  
  706.     FileIsOpen = NO;
  707.     FileLocation = fileAtStart;
  708.  
  709.     return self;
  710. }
  711.  
  712.  
  713. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  714. //    Routine:        CloseAndDelete
  715. //    Parameters:    none
  716. //    Returns:        self
  717. //    Stores:        the error we got back from the system routine.  (don't depend on this)
  718. //    Description:
  719. //        This closes the file, and then deletes it.
  720. //    Bugs:
  721. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  722. - CloseAndDelete
  723. {
  724.     Integer status;
  725.     [self ResetResults];
  726.     
  727.     [self Close];
  728.     status = remove(FileName);
  729.     if (status != 0)
  730.     {
  731.         [self StoreErrorCode: ERR_CANTDELETE AndText: "Could not delete file. unknown why"];
  732.         [self StoreInteger: status];
  733.     }
  734.     else
  735.         [self StoreErrorCode: ERR_OK AndText: "Deleted the file just fine"];
  736.  
  737.     FileIsOpen = NO;
  738.     FileLocation = fileAtStart;
  739.  
  740.     return self;
  741. }
  742.  
  743.  
  744. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  745. //    Routine:        free:
  746. //    Parameters:    none
  747. //    Returns:        self
  748. //    Stores:        none
  749. //    Description:
  750. //        This frees the object, which involves closing our connection to the physical
  751. //        file, WITHOUT SAVING, and then disposing of our instance variables,
  752. //        and then freeing our parent.
  753. //    Bugs:
  754. //        The call to close is commented out here because it's causing trouble if you
  755. //        say: [myFile CloseAndSave] ;  [myFile free];  Streams problem.  we SHOULD
  756. //        be somehow nulling the stream, in the Close methods, and closing here only if
  757. //        it isn't null.
  758. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  759. - free
  760. {
  761.     //[self Close];
  762.     free(FileName);
  763.     return [super free];
  764. }
  765.  
  766.  
  767. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  768. //    Routine:        AdvanceBytes:
  769. //    Parameters:    the number of bytes we should advance
  770. //    Returns:        self
  771. //    Stores:        none
  772. //    Description:
  773. //        This changes our current position in the file by advancing us up a specified number
  774. //        of bytes in it. We add an exception handler partially for the ease so we don't
  775. //        have to do the error checking ourselves.  Partially because it allows us to
  776. //        check for other exceptions and kinda trap for them.  And partially for the
  777. //        novelty of it.
  778. //    Bugs:
  779. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  780. - AdvanceBytes: (FilePosDelta) byteLoc;
  781. {
  782.     [self ResetResults];
  783.  
  784.     if (TheFile == NULL)
  785.         [self StoreErrorCode: ERR_FILENOTOPEN  AndText: "The file wasn't even open!"];
  786.     else
  787.     {
  788.         //
  789.         //    Try to advance the requested number of bytes.  If an exception occurrs,
  790.         //    and it's a seek error, just stick us at the end quietly.  Otherwise, store
  791.         //    an error code and leave things as they are.  
  792.         //
  793.         NX_DURING
  794.             NXSeek(TheFile, byteLoc, NX_FROMCURRENT);
  795.             [self StoreErrorCode: ERR_PEACHY AndText: "We found what we NXsaught."];
  796.         NX_HANDLER
  797.             switch(NXLocalHandler.code)
  798.             {
  799.                 case NX_illegalSeek:
  800.                     NXSeek(TheFile, 0, NX_FROMEND);
  801.                     [self StoreErrorCode: ERR_OK AndText: "Moved to the end."];
  802.                     FileLocation = fileAtEOF;
  803.                     break;
  804.                 default :
  805.                     [self StoreErrorCode: ERR_BADADVANCE
  806.                         AndText: "A unknown exception occurred when advancing."];
  807.                     break;
  808.             }
  809.         NX_ENDHANDLER
  810.     }
  811.     return self;
  812. }
  813.  
  814.  
  815.  
  816. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. //    Routine:        BackupBytes:
  818. //    Parameters:    the number of bytes we should backup
  819. //    Returns:        self
  820. //    Stores:        none
  821. //    Description:
  822. //        This changes our current position in the file by backing us up a specified number
  823. //        of bytes in it.  We set up an exception handler to deal with the case if the
  824. //        user tries to seek before the beginning.  We could, perhaps, do the traping
  825. //        ourselves (compute current loc, distance from beginning, whether the byteLoc
  826. //        falls within that request... etc), but this seems easier, and deals with any other
  827. //        unexpected exceptions too.
  828. //    Bugs:
  829. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  830. - BackupBytes: (FilePosDelta) byteLoc;
  831. {
  832.     [self ResetResults];
  833.  
  834.     if (TheFile == NULL)
  835.         [self StoreErrorCode: ERR_FILENOTOPEN  AndText: "The file wasn't even open!"];
  836.     else
  837.     {
  838.         //
  839.         //    Try to backup the requested number of bytes.  If an exception occurrs,
  840.         //    and it's a seek error, just stick us at the beginning quietly.  Otherwise, store
  841.         //    an error code and leave things as they are.  
  842.         //
  843.         NX_DURING
  844.             NXSeek(TheFile, -byteLoc, NX_FROMCURRENT);
  845.             [self StoreErrorCode: ERR_OK AndText: "We found what we NXsaught."];
  846.         NX_HANDLER
  847.             switch(NXLocalHandler.code)
  848.             {
  849.                 case NX_illegalSeek:
  850.                     NXSeek(TheFile, 0, NX_FROMSTART);
  851.                     [self StoreErrorCode: ERR_OK AndText: "Moved to beginning."];
  852.                     FileLocation = fileAtEOF;
  853.                     break;
  854.                 default :
  855.                     [self StoreErrorCode: ERR_BADBACKUP
  856.                         AndText: "A unknown exception occurred when backing up."];
  857.                     break;
  858.             }
  859.         NX_ENDHANDLER
  860.     }
  861.     return self;
  862. }
  863.  
  864.  
  865. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  866. //    Routine:        GetBasename
  867. //    Parameters:    none
  868. //    Returns:        the copy of a string containing the current filename's basename
  869. //    Stores:        A pointer to the same string we return
  870. //    Description:
  871. //        This simply  extracts the basename of the current file name.  The basename is
  872. //        the part of the name that comes after thedirectory names, but before the extension.
  873. //        If we are using the file  /foo/bar/hotfile.rtf, this returns hotfile
  874. //    Bugs:
  875. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  876. - (CString) GetBasename
  877. {
  878.     CString    lastSlash, lastDot, tempName, finish, start;
  879.     Integer    nameSize;
  880.     [self ResetResults];
  881.     //
  882.     //    Determine the length of the basename by figuring out where its start is
  883.     //    (either right after the /, or at the start) and the end (before . or at the end)
  884.     //
  885.     lastSlash = strrchr(FileName, '/');
  886.     lastDot = strrchr(FileName, '.');
  887.     if (lastSlash == NullCString)
  888.         start = FileName;
  889.     else
  890.         start = &lastSlash[1];
  891.     
  892.     if ((lastDot == NullCString) || (lastDot < lastSlash))
  893.         finish = &FileName[strlen(FileName)];
  894.     else
  895.         finish = lastDot;
  896.  
  897.     nameSize = finish - start;
  898.     //
  899.     //    Allocate the proper space for the basename, store the text, and return it.
  900.     //
  901.     tempName = (CString) malloc(nameSize+1);
  902.     strncpy(tempName, start, nameSize);
  903.     tempName[nameSize] = EndOfCString;
  904.     
  905.     [self StoreErrorCode: ERR_OK AndText: "Located whatever basename was to be found."];
  906.     [self StoreCString: tempName];
  907.     return tempName;
  908. }
  909.  
  910.  
  911. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  912. //    Routine:        GetCurrentPosition
  913. //    Parameters:    none
  914. //    Returns:        A position in the file
  915. //    Stores:        A position in the file as an Integer
  916. //    Description:
  917. //        this returns a FilePos value which indicates a current position in the file, as
  918. //        a count of the number of bytes since the beginning.
  919. //    Bugs:
  920. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  921. - (FilePos) GetCurrentPosition
  922. {
  923.     FilePos    pos;
  924.     [self ResetResults];
  925.     if (TheFile == NULL)
  926.     {
  927.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "No position in an unopened file."];
  928.         pos =  0;
  929.     }
  930.     else
  931.     {
  932.         pos =  NXTell(TheFile);
  933.         [self StoreErrorCode: ERR_OK AndText: "Got the file position."];
  934.     }
  935.     [self StoreInteger: pos];
  936.     return pos;
  937. }
  938.  
  939.  
  940. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  941. //    Routine:        GetExtension
  942. //    Parameters:    none
  943. //    Returns:        the copy of a string containing the current filename's extension
  944. //    Stores:        A pointer to the same string we return
  945. //    Description:
  946. //        This simply  extracts the extension of the current file name.  The extension is
  947. //        the part of the name that comes after the last . in the filename.  If there is no
  948. //        extension, this will simply return an empty string.
  949. //        If we are using the file  /foo/bar/hotfile.rtf, this returns rtf
  950. //    Bugs:
  951. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  952. - (CString) GetExtension
  953. {
  954.     //
  955.     //    Determine where the last / and . are. We need the / to be sure we don't get a . further
  956.     //    up in the path somewhere.
  957.     //
  958.     CString    lastSlash, lastDot, start, tempName;
  959.  
  960.     [self ResetResults];
  961.     //
  962.     //     Locate the last . in the file name, and the last /.  If we found no dot, or it came
  963.     //    before the slash in the name, then there is no extension, so start with a null CString.
  964.     //    otherwise, set the start of the exension to just after the last dot.
  965.     //    
  966.     lastSlash = strrchr(FileName, '/');
  967.     lastDot = strrchr(FileName, '.');
  968.     if ((lastDot == NullCString) || (lastDot < lastSlash))
  969.         start = NullCString;
  970.     else
  971.         start = &lastDot[1];
  972.     //
  973.     //    Allocate space for the extension in a temporary string, and copy it into
  974.     //    TempName.
  975.     //
  976.     tempName = (CString) malloc(strlen(start)+1);
  977.     strcpy(tempName, start);
  978.     [self StoreErrorCode: ERR_OK AndText: "Located whatever extension was to be found."];
  979.     [self StoreCString: tempName];
  980.     return tempName;
  981. }
  982.  
  983.  
  984. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. //    Routine:        GetFilename
  986. //    Parameters:    none
  987. //    Returns:        the copy of a string containing the full filename, without 
  988. //    Stores:        A pointer to the same string we return
  989. //    Description:
  990. //    this returns the path to the file that we are using without including the file name
  991. //    itselfor the slash before the filename.  If there are no /'s (and thus, oddly, no directories
  992. //    refered to), a null string is returned. If we are using the file  /foo/bar/hotfile.rtf, this
  993. //    returns hotfile.rtf
  994. //    Bugs:
  995. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  996. - (CString) GetFilename
  997. {
  998.     CString    start;
  999.     CString    tempName;
  1000.     [self ResetResults];
  1001.     //
  1002.     //    Locate the slash before the Filename, and make start point after it
  1003.     //    (which happens to be the start of our filename)
  1004.     //
  1005.     start = strrchr(FileName, '/');
  1006.     if (start != NullCString)
  1007.         start = &start[1];
  1008.     else
  1009.         start = FileName;
  1010.     //
  1011.     //    Allocate the proper space for the filename, copy the text, and return it.
  1012.     //
  1013.     tempName = (CString) malloc(strlen(start)+1);
  1014.     strcpy(tempName,  start);
  1015.     [self StoreErrorCode: ERR_OK  AndText: "Extracted the filename"];
  1016.     [self StoreCString: tempName];
  1017.     return tempName;
  1018. }
  1019.  
  1020.  
  1021. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1022. //    Routine:        GetDirectory
  1023. //    Parameters:    none
  1024. //    Returns:        the copy of a string containing the pathname to this directory
  1025. //    Stores:        A pointer to the same string we return
  1026. //    Description:
  1027. //    this returns the path to the file that we are using without including the file name
  1028. //    itselfor the slash before the filename.  If there are no /'s (and thus, oddly, no directories
  1029. //    refered to), a null string is returned.  If we are using the filen  /foo/bar/hotfile.rtf, this returns
  1030. //    /foo/bar
  1031. //    Bugs:
  1032. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1033. - (CString) GetDirectory
  1034. {
  1035.     //
  1036.     //    Declare a temporary string to store the file name, clear the results, and copy
  1037.     //    the actual file name into the temp string.
  1038.     //
  1039.     CString    lastSlash;
  1040.     CString    tempName = (CString) malloc(strlen(FileName)+1);
  1041.     [self ResetResults];
  1042.     strcpy(tempName, FileName);
  1043.     //
  1044.     //    Locate the last slash in the path name.  If we find it, make it the end of the string instad,
  1045.     //    otherwise clear the whole string.  Return it in any case.
  1046.     //
  1047.     lastSlash = strrchr(tempName, '/');
  1048.     if (lastSlash != NullCString)
  1049.     {
  1050.         lastSlash[0] = EndOfCString;
  1051.         [self StoreErrorCode:  ERR_OK AndText: "Got the directory"];
  1052.     }
  1053.     else
  1054.     {
  1055.         tempName[0]=EndOfCString;
  1056.         [self StoreErrorCode:  ERR_NODIRECTORY AndText: "There were no directory names"];
  1057.     }
  1058.     [self StoreCString: tempName];
  1059.     return tempName;
  1060. }
  1061.  
  1062.  
  1063. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1064. //    Routine:        GetPathname:
  1065. //    Parameters:    none
  1066. //    Returns:        the copy of a string containing the pathname to this file
  1067. //    Stores:        A pointer to the same string we return
  1068. //    Description:
  1069. //        This merely makes a copy of the string that we have stored for the pathname
  1070. //        and returns it to the caller.  Given the filename  /foo/bar/hotfile.rtf, this returns
  1071. //        /foo/bar/hotfile.rtf
  1072. //    Bugs:
  1073. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1074. - (CString) GetPathname
  1075. {
  1076.     CString    tempName;
  1077.     [self ResetResults];
  1078.     //
  1079.     //    Allocate the proper space for the pahtname, store the text, and return it.
  1080.     //
  1081.     tempName = (CString) malloc(strlen(FileName)+1);
  1082.     strcpy(tempName, FileName);
  1083.     [self StoreErrorCode: ERR_OK AndText: "Gotcha your path"];
  1084.     [self StoreCString: tempName];
  1085.     return tempName;
  1086. }
  1087.  
  1088.  
  1089. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1090. //    Routine:        MoveTo:
  1091. //    Parameters:    the byte position we should move to in the file
  1092. //    Returns:        self
  1093. //    Stores:        The position we moved to
  1094. //    Description:
  1095. //        This changes our position in the file to the position byteLoc bytes from the
  1096. //        beginning of the file.  The new position in the file is stored before we return.
  1097. //        Deal with exceptions being raised around the NXSeek code.  If an error occurs,
  1098. //        then we will assume that it's because we tried to move past the eof, and so we
  1099. //        set the position at the end of a file.  if an unknown exception occurs, do nothing.
  1100. //    Bugs:
  1101. //        I don't know if the assumption that an NX_illegalSeek exception necessarily means
  1102. //        we tried to go past the end of the stream.  If not, there's problems here.
  1103. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1104. - (id) MoveTo: (PositiveInteger) byteLoc
  1105. {
  1106.     Boolean result;
  1107.     [self ResetResults];
  1108.     
  1109.     if (TheFile == NULL)
  1110.         [self StoreErrorCode: ERR_FILENOTOPEN
  1111.             AndText: "The file wasn't even open!  How d'ya expect me to move around in it?!"];
  1112.     else if (AccessMode == FILE_APPEND)
  1113.         [self StoreErrorCode: ERR_FILEAPPENDONLY
  1114.             AndText: "Can not change position in a file set for only appending"];
  1115.     else
  1116.     {
  1117.         //
  1118.         //    Try to move the requested number of bytes.  If an exception occurrs,
  1119.         //    and it's a seek error, just stick us at the end quietly (assume the
  1120.         //    error was due to running over the end.  Otherwise, store
  1121.         //    an error code and leave things as they are.  
  1122.         //
  1123.         NX_DURING
  1124.             NXSeek(TheFile, byteLoc, NX_FROMSTART);
  1125.             [self StoreErrorCode: ERR_OK AndText: "Moved OK"];
  1126.         NX_HANDLER
  1127.             switch(NXLocalHandler.code)
  1128.             {
  1129.                 case NX_illegalSeek:
  1130.                     NXSeek(TheFile, 0, NX_FROMEND);
  1131.                     [self StoreErrorCode: ERR_OK AndText: "Moved to the end."];
  1132.                     FileLocation = fileAtEOF;
  1133.                     break;
  1134.                 default :
  1135.                     [self StoreErrorCode: ERR_BADADVANCE
  1136.                         AndText: "A unknown exception occurred when advancing."];
  1137.                     break;
  1138.             }
  1139.         NX_ENDHANDLER
  1140.  
  1141.         result = NXAtEOS(TheFile);
  1142.         if (result != NO)
  1143.             FileLocation = fileAtEOF;
  1144.         else if ( NXTell(TheFile) == 0)
  1145.             FileLocation = fileAtStart;
  1146.         else
  1147.             FileLocation = fileInMiddle;
  1148.  
  1149.  
  1150.         [self StorePositiveInteger: NXTell(TheFile)];
  1151.     }
  1152.     return self;
  1153. }
  1154.  
  1155.  
  1156. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1157. //    Routine:        ReadByte
  1158. //    Parameters:    none
  1159. //    Returns:        the byte we read
  1160. //    Stores:        The byte we read
  1161. //                YES if EOF was encountered
  1162. //    Description:
  1163. //        This reads a byte from our file. If all goes well, we return the byte.  Otherwise,
  1164. //        we return 0 and store an error
  1165. //    Bugs:
  1166. //        BOOL NXAtEOS(NXStream *stream)
  1167. //        Says it should not be used on streams open for writing.  What about read/write?
  1168. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1169. - (Byte) ReadByte
  1170. {
  1171.     Byte byteIn = 0;
  1172.     Boolean    result;
  1173.     
  1174.     [self ResetResults];
  1175.  
  1176.     if (TheFile == NULL)
  1177.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1178.     else if ((AccessMode == FILE_WRITE) || (AccessMode == FILE_APPEND))
  1179.         [self StoreErrorCode: ERR_FILEWRITEONLY
  1180.             AndText: "Can not read from a file set for only appending or writing"];
  1181.     else
  1182.     {
  1183.         result = NXAtEOS(TheFile);
  1184.         if (result != NO)
  1185.         {
  1186.             [self StoreErrorCode: ERR_EOF AndText: "End of file found"];
  1187.             FileLocation = fileAtEOF;
  1188.             [self StorePositiveInteger: 0];
  1189.             [self PutBoolean: YES Into: SECOND_RESULT];
  1190.         }
  1191.         else
  1192.         {
  1193.             byteIn = NXGetc(TheFile);
  1194.             [self StoreErrorCode: ERR_OK AndText: "Read the byte"];
  1195.             [self StorePositiveInteger: byteIn];
  1196.             [self PutBoolean: NO Into: SECOND_RESULT];
  1197.         }
  1198.     }
  1199.     return byteIn;
  1200. }
  1201.  
  1202. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1203. //    Routine:        Read:BytesInto:
  1204. //    Parameters:    the number of bytes we are to read
  1205. //                the buffer that we are to read info
  1206. //    Returns:        self
  1207. //    Stores:        The number of bytes we succesfully read
  1208. //                YES if we found EOF at the end of the current read
  1209. //    Description:
  1210. //        This attempts to read in numBytes bytes from our file into the buffer.  It does no
  1211. //        checking to assure that the buffer is of the proper size.  After reading the bytes, it
  1212. //        stores the number of bytes it succeeded in reading.  If the number of bytes written
  1213. //        is not equal to the number requested, an error is stored.
  1214. //    Bugs:
  1215. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1216. - (id) Read: (PositiveInteger) numBytes BytesInto: (ByteString) buffer
  1217. {
  1218.     PositiveInteger    BytesRead;
  1219.     Boolean            result;
  1220.     
  1221.     [self ResetResults];
  1222.  
  1223.     if (TheFile == NULL)
  1224.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1225.     else if ((AccessMode == FILE_WRITE) || (AccessMode == FILE_APPEND))
  1226.         [self StoreErrorCode: ERR_FILEWRITEONLY
  1227.             AndText: "Can not read from a file set for only appending or writing"];
  1228.     else
  1229.     {
  1230.         result = NXAtEOS(TheFile);
  1231.         if (result != NO)
  1232.         {
  1233.             [self StoreErrorCode: ERR_EOF AndText: "End of file found"];
  1234.             FileLocation = fileAtEOF;
  1235.             [self StorePositiveInteger: 0];
  1236.             [self PutBoolean: YES Into: SECOND_RESULT];
  1237.         }
  1238.         else
  1239.         {
  1240.             BytesRead = NXRead(TheFile, buffer, numBytes);
  1241.             //
  1242.             //    Deal with the consequences of our actions
  1243.             //
  1244.             if (BytesRead != numBytes)
  1245.                 [self StoreErrorCode: ERR_READINGERROR AndText: "Read the wrong number of bytes"];
  1246.             else
  1247.                 [self StoreErrorCode: ERR_OK AndText: "Read the bytes."];
  1248.             [self StorePositiveInteger: BytesRead];
  1249.             [self PutBoolean: NO Into: SECOND_RESULT];
  1250.         }
  1251.     }
  1252.     return self;
  1253. }
  1254.  
  1255.  
  1256. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1257. //    Routine:        WriteByte
  1258. //    Parameters:    the byte we are to write
  1259. //    Returns:        self
  1260. //    Stores:        The byte we think we wrote
  1261. //    Description:
  1262. //        This writes a specified byte to our file.  It then checks to make sure we wrote
  1263. //        that byte.  If we failed to do that, we generate an error.
  1264. //    Bugs:
  1265. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1266. - (id) WriteByte: (Byte) theByte
  1267. {
  1268.     PositiveInteger byteOut;
  1269.     
  1270.     [self ResetResults];
  1271.  
  1272.     if (TheFile == NULL)
  1273.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1274.     else if (AccessMode == FILE_READ)
  1275.         [self StoreErrorCode: ERR_FILEREADONLY AndText: "Can not write to read-only file"];
  1276.     else
  1277.     {
  1278.         byteOut = NXPutc(TheFile, theByte);
  1279.         if (byteOut == theByte) 
  1280.             [self StoreErrorCode: ERR_OK AndText: "Wrote the byte"];
  1281.         else
  1282.             [self StoreErrorCode: ERR_WROTEBADCHAR AndText: "Wrote the wrong byte"];
  1283.         [self StorePositiveInteger: byteOut];
  1284.     }
  1285.     return self;
  1286. }
  1287.  
  1288.  
  1289.  
  1290. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1291. //    Routine:        Write:BytesFrom:
  1292. //    Parameters:    the number of bytes we are to write
  1293. //                the buffer that we are to write from
  1294. //    Returns:        self
  1295. //    Stores:        The number of bytes we succesfully wrote
  1296. //    Description:
  1297. //        This writes a specified number of bytes from the buffer we have been passed to
  1298. //        the file that we manipulate.  If we fail to write all the bytes requested, we store an
  1299. //        error.  We always store the number of bytes we wrote.
  1300. //    Bugs:
  1301. //        We never flush the data out (NXFlush does naught for a memory stream)
  1302. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1303. - (id) Write: (PositiveInteger) numBytes BytesFrom: (ByteString) buffer
  1304. {
  1305.     PositiveInteger    bytesWrote;
  1306.     
  1307.     [self ResetResults];
  1308.  
  1309.     if (TheFile == NULL)
  1310.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1311.     else if (AccessMode == FILE_READ)
  1312.         [self StoreErrorCode: ERR_FILEREADONLY AndText: "Can not write to read-only file"];
  1313.     else
  1314.     {
  1315.         bytesWrote = NXWrite(TheFile, buffer, numBytes);
  1316.         //
  1317.         //    Deal with the consequences of our actions
  1318.         //
  1319.         if (bytesWrote != numBytes)
  1320.             [self StoreErrorCode: ERR_WRITINGERROR
  1321.                 AndText: "Wrote the wrong number of bytes"];
  1322.         else
  1323.             [self StoreErrorCode: ERR_OK AndText: "Wrote the bytes."];
  1324.         [self StorePositiveInteger: bytesWrote];
  1325.     }
  1326.     return self;
  1327. }
  1328.  
  1329.  
  1330. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1331. //    Method:        FileSize
  1332. //    Parameters:    none
  1333. //    Returns:        An integer reflecting the size of the file.  Set to 0 if an error occured
  1334. //    Stores:        The return value, if all went well, otherwise nothing
  1335. //    Description:
  1336. //        This determines how many bytes long the file that this object manipulates is,
  1337. //        and returns this number to the caller.
  1338. //    Bugs:
  1339. //        Only usable if the file has been opened...
  1340. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1341. - (PositiveInteger) FileSize
  1342. {
  1343.     PositiveInteger    currentLoc, eofLoc;
  1344.     
  1345.     [self ResetResults];
  1346.     if (TheFile == NULL)
  1347.     {
  1348.         [self StoreErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened."];
  1349.         eofLoc = 0;
  1350.         [self StorePositiveInteger: 0];
  1351.     }
  1352.     else
  1353.     {
  1354.         currentLoc = NXTell(TheFile);
  1355.         NXSeek(TheFile, 0, NX_FROMEND);
  1356.         eofLoc = NXTell(TheFile);
  1357.         NXSeek(TheFile, currentLoc, NX_FROMSTART);
  1358.         [self StoreErrorCode: ERR_OK AndText: "Obtained size of file."];
  1359.         [self StorePositiveInteger: eofLoc];
  1360.     }
  1361.     return eofLoc;
  1362. }
  1363.  
  1364.  
  1365. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1366. //    Method:        FileInfo
  1367. //    Parameters:    none
  1368. //    Returns:        self
  1369. //    Stores:        the access mode is stored in return position 1
  1370. //                a pointer to an OS-dependant structure is in 2
  1371. //    Description:
  1372. //        This returns information to the caller that isn't accessable through other
  1373. //        methods.  At this point, it returns the access method for the file, currently being
  1374. //        used.  It also returns a pointer to a stat structure (see the man page for stat).
  1375. //        The stat structure may be replaced by a better structure in a future
  1376. //        version
  1377. //    Bugs:
  1378. //        info like file size won't be accurate to the caller.
  1379. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1380. -  FileInfo
  1381. {
  1382.      struct stat *statbuf = (struct stat *) malloc(sizeof(struct stat));
  1383.     
  1384.     if (stat(FileName, statbuf) != 0)
  1385.         [self StoreErrorCode: ERR_CANTGETINFO AndText: "Could not get machine dep. info"];
  1386.     else
  1387.     {
  1388.         [self StoreErrorCode: ERR_OK AndText: "The info is yours!"];
  1389.         [self PutInteger: AccessMode Into: FIRST_RESULT];
  1390.         [self CopyPointer: (Pointer) statbuf WithLength: sizeof(struct stat) Into: SECOND_RESULT];
  1391.          }
  1392.     free((char*) statbuf);
  1393.     return self;
  1394. }
  1395.  
  1396.  
  1397. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1398. //    Method:        SameFileAs
  1399. //    Parameters:    the path to another file
  1400. //    Returns:        A boolean value.  yes indicates that the pathname refers to the same
  1401. //                file this object is accessing.  no means either they are different or
  1402. //                the other file does not exist. (or that this one doesn't exist)
  1403. //    Stores:        This boolean.
  1404. //    Description:
  1405. //        Used to determine if some other file is the same as this one..  Pass the name of
  1406. //        the other file with a path, and this will check to see it if it refers to the same
  1407. //        file that it is using.  Note that this doesn't understand symbolic links, really.
  1408. //    Bugs:
  1409. //        Inadequately deals with the negative cases where one or both files might not
  1410. //        actually exist.
  1411. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1412. -  (Boolean) SameFileAs: (CString) someOtherFile
  1413. {
  1414.      struct stat *statbuf = (struct stat *) malloc(sizeof(struct stat));
  1415.     CString     pathToFile = [self GetFullPathFrom:  someOtherFile];
  1416.     ErrorCode result;
  1417.     Boolean answer = NO;
  1418.     
  1419.     if (stat(pathToFile, statbuf) != 0)
  1420.         result = -1;
  1421.     else
  1422.     {
  1423.         if (TheInode == statbuf->st_ino)
  1424.             result = 0;
  1425.         else
  1426.             result = 1;
  1427.     }
  1428.     FreeCString(pathToFile);
  1429.     //    92.01.01    djb    Added freeing of statbuf to remove a memory leak.
  1430.     free((char*) statbuf);
  1431.     
  1432.     switch (result)
  1433.     {
  1434.         case -1:
  1435.             [self StoreErrorCode: ERR_OK AndText: "The file does not even exist!"];
  1436.             answer = NO;
  1437.             break;
  1438.         case 0:
  1439.             [self StoreErrorCode: ERR_OK AndText: "The info is yours!"];
  1440.             answer = YES;
  1441.             break;
  1442.         case 1:
  1443.             [self StoreErrorCode: ERR_OK AndText: "The info is yours!"];
  1444.             answer = NO;
  1445.             break;
  1446.     }
  1447.     [self StoreBoolean: answer];
  1448.     return answer;
  1449. }
  1450.  
  1451.  
  1452.  
  1453. @@end@
  1454.  
  1455.  
  1456. 1.7
  1457. log
  1458. @Sun Jan 10 15:07:54 PST 1993
  1459. @
  1460. text
  1461. @d4 2
  1462. a5 2
  1463.     This is $Revision: 1.6 $ of this file
  1464.     It was last modified by $Author: death $ on $Date: 92/07/26 13:58:06 $
  1465. d8 3
  1466. d412 2
  1467. a413 1
  1468.     sprintf(FileName, "/tmp/TempFileDataP%dS%dU%d",
  1469. @
  1470.  
  1471.  
  1472. 1.6
  1473. log
  1474. @Update so all works with the font converter...
  1475.  
  1476. @
  1477. text
  1478. @d4 2
  1479. a5 2
  1480.     This is $Revision: 1.4 $ of this file
  1481.     It was last modified by $Author: death $ on $Date: 92/04/05 22:51:36 $
  1482. d8 4
  1483. d39 5
  1484. d395 5
  1485. d403 2
  1486. d406 19
  1487. a424 1
  1488.     FileName = tmpnam(NULL);
  1489. d1043 1
  1490. d1078 7
  1491. d1086 1
  1492. a1102 1
  1493. //        We don't yet write the EOF flag.
  1494. d1109 1
  1495. d1120 15
  1496. a1134 4
  1497.         byteIn = NXGetc(TheFile);
  1498.         [self StoreErrorCode: ERR_OK AndText: "Read the byte"];
  1499.         [self StorePositiveInteger: byteIn];
  1500.         [self PutBoolean: NO Into: SECOND_RESULT];
  1501. a1151 1
  1502. //        We don't watch for the EOF value yet... //@@@@@@@@@@@@@@@@
  1503. d1156 1
  1504. d1167 8
  1505. a1174 6
  1506.         BytesRead = NXRead(TheFile, buffer, numBytes);
  1507.         //
  1508.         //    Deal with the consequences of our actions
  1509.         //
  1510.         if (BytesRead != numBytes)
  1511.             [self StoreErrorCode: ERR_READINGERROR AndText: "Read the wrong number of bytes"];
  1512. d1176 12
  1513. a1187 3
  1514.             [self StoreErrorCode: ERR_OK AndText: "Wrote the bytes."];
  1515.         [self StorePositiveInteger: BytesRead];
  1516.         [self PutBoolean: NO Into: SECOND_RESULT];
  1517. d1366 2
  1518. @
  1519.  
  1520.  
  1521. 1.5
  1522. log
  1523. @misc changes (intermediate version).
  1524. @
  1525. text
  1526. @d27 2
  1527. a28 2
  1528. #import "Reply.h"
  1529. #import <stdio.h>    // for fopen, among others
  1530. d32 3
  1531. a34 1
  1532. #import <libc.h>            //for getwd
  1533. d37 3
  1534. d41 38
  1535. d80 13
  1536. a92 1
  1537. char    strrpos(char* s, char c)
  1538. d94 17
  1539. a110 7
  1540.     Cstring result;
  1541.     
  1542.     result = rindex(s, c);
  1543.     if (result == NULL)
  1544.         return -1;
  1545.     else
  1546.         return (result - s);
  1547. d113 38
  1548. a152 2
  1549. //    General comment:
  1550. //                If errors occurred when starting up, nothing is stored
  1551. d154 13
  1552. a166 10
  1553.  
  1554. /**********************************************************************************
  1555.     When called, this opens the specified file, if possible, and sets up the object.
  1556.     Bugs: too minimal.  Header comment sucks.
  1557.     For religious as well as sanity reasons, I dislike multiple exit points.  Thi is just
  1558.     to poin out that there are three returns in here.  There should be one... mayhaps
  1559.     allocate the reply objects, and then return whichever got allocated at the end...
  1560.     Can we free ourselves safely at the end if we fail?? =(
  1561. **********************************************************************************/
  1562. - (id) openFile: (const char *) workingName For: (long int) operation
  1563. a167 8
  1564.     id    result = NULL;
  1565.     FILE*     tempfd;
  1566.     char    pathname[MAXPATHLEN];    
  1567.     int        pathresult;
  1568.     [super init];
  1569.     
  1570. /*    We should make the workingName a full pathname if it isn't already... */
  1571.     
  1572. d169 2
  1573. a170 1
  1574.     //    copy the string into our instance variable, and store the operation requested
  1575. d172 3
  1576. a174 1
  1577.     if (workingName[0] != '/')
  1578. d176 1
  1579. a176 2
  1580.          pathresult = getwd(pathname);
  1581.         if (pathresult != 0)
  1582. d178 4
  1583. a181 2
  1584.             fileName = (Cstring) malloc(strlen(pathname)+1+strlen(workingName) + 1);
  1585.             sprintf(fileName, "%s/%s", pathname, workingName);
  1586. d183 1
  1587. a183 1
  1588.         else    // we may be in trouble, so just use the file name by default
  1589. d185 4
  1590. a188 2
  1591.             fileName = (Cstring) malloc(strlen(workingName) + 1);
  1592.             strcpy(fileName, workingName);
  1593. d190 5
  1594. d196 25
  1595. a220 1
  1596.     else    // path is rooted, so just use it literally...
  1597. d222 14
  1598. a235 2
  1599.         fileName = (Cstring) malloc(strlen(workingName) + 1);
  1600.         strcpy(fileName, workingName);
  1601. d237 26
  1602. a262 2
  1603.     accessType = operation;
  1604.     theFile = NULL;
  1605. d264 2
  1606. a265 1
  1607.     //    Open the file, reflecting the access method we want to have.
  1608. d267 1
  1609. a267 1
  1610.     switch (operation)
  1611. d269 24
  1612. a292 31
  1613.         case FILE_READ:
  1614.             theFile = NXMapFile(fileName, NX_READONLY);
  1615.             break;
  1616.         case FILE_WRITE:
  1617.             // try to create the file, or clear it.  If that works, close it, and open it as a stream.
  1618.             //Note for future versions: Maybe there's a nice NX..stream thing to take care of this.
  1619.             tempfd = fopen(fileName, "w+");
  1620.             if (tempfd  !=NULL)
  1621.             {
  1622.                 fclose(tempfd);
  1623.                 theFile = NXMapFile(fileName, NX_WRITEONLY);
  1624.             }
  1625.                 // should generate an error reply here            break;
  1626.         case    FILE_READWRITE:
  1627.             tempfd = fopen(fileName, "w+");
  1628.             if (tempfd !=NULL)
  1629.             {
  1630.                 fclose(tempfd);
  1631.                 theFile = NXMapFile(fileName, NX_READWRITE);
  1632.             }
  1633.                 // should generate an error reply here
  1634.             break;
  1635. /*    APPENDING not supported in current version... =(
  1636.         case FILE_APPEND
  1637.             theFile = fopen(fileName, "a");
  1638.             break;
  1639. */
  1640.         default:
  1641.             result =  [[Reply alloc]     initErrorWithCode: ERR_BADACCESS
  1642.                 Text: "An invalid access operation was requested. No file opened."];
  1643.             break;
  1644. a295 1
  1645.     //    otherwise, generate a positive one.
  1646. d297 3
  1647. a299 4
  1648.     if (theFile == NULL)
  1649.             // BUG: We overwrite the text generated in default, above!!
  1650.             result =  [[Reply alloc]     initErrorWithCode: ERR_CANTOPEN
  1651.                 Text: "The specified file could not be opened (bad permissions?  Bad path?)"];
  1652. d301 24
  1653. a324 5
  1654.         result =  [[Reply alloc]     initReplyWithCode: ERR_PEACHY
  1655.                 Text: "I found no errors (didn't look neither) so all must be OK."
  1656.                 Data: (void*) self
  1657.                 Type: TYPE_OBJECT];
  1658.     return result;
  1659. d328 11
  1660. a338 4
  1661. /**********************************************************************************
  1662.     This simply calls openFile:For: with a default operation value.
  1663. **********************************************************************************/
  1664. - (id) openFile: (const char *) filename
  1665. d340 26
  1666. a365 1
  1667.     return [self openFile: filename For: FILE_READWRITE];
  1668. d369 19
  1669. a387 6
  1670. /**********************************************************************************
  1671.     This is a dummy routine provided to provide support for NeXT style standard methods
  1672.     (i.e. objects havng an 'init...' method).  It just calls the real init method (which I
  1673.     enourage you to use because of its better name =), openFile:For:
  1674. **********************************************************************************/
  1675. - (id) initFile: (const char*) workingName For: (long int) operation
  1676. d389 7
  1677. a395 1
  1678.     return [self openFile: workingName For: operation];
  1679. d399 19
  1680. a417 4
  1681. /*============================================================*\
  1682.     Close the file, deallocate the string value, and free the object.
  1683. \*============================================================*/
  1684. - (id) closeFile
  1685. d419 8
  1686. a426 1
  1687.     return [self close];        // get rid of this method, dude
  1688. d429 16
  1689. a444 4
  1690. /*============================================================*\
  1691.     Close the file, deallocate the string value, and free the object.
  1692. \*============================================================*/
  1693. - (id) close
  1694. d446 38
  1695. a483 1
  1696.     if (theFile != NULL)
  1697. d485 2
  1698. a486 3
  1699.         // check return
  1700.         NXSaveToFile(theFile, fileName);
  1701.         NXCloseMemory(theFile, NX_FREEBUFFER);
  1702. d488 5
  1703. a492 2
  1704.     free(fileName);
  1705.     return [super free];
  1706. d495 1
  1707. d497 15
  1708. a511 3
  1709. //    Routine: advanceBytes: 
  1710. //    Parameters: the number of bytes to advance in the file
  1711. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)
  1712. d513 1
  1713. a513 1
  1714. - (id) advanceBytes: (FilePosDelta) byteLoc;
  1715. d515 13
  1716. a527 5
  1717.     id result;
  1718.     
  1719.     if (theFile == NULL)
  1720.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  1721.                 Text: "The file wasn't even open!  How d'you expect me to move around in it?!"];
  1722. d530 19
  1723. a548 3
  1724.         NXSeek(theFile, byteLoc, NX_FROMCURRENT);
  1725.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  1726.                 Text: "We found what we NXsaught."];
  1727. d550 1
  1728. a550 1
  1729.     return result;
  1730. d553 2
  1731. d558 7
  1732. a564 3
  1733. //    Routine: backupBytes: 
  1734. //    Parameters: the number of bytes to advance in the file
  1735. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)
  1736. d566 1
  1737. a566 1
  1738. - (id) backupBytes: (FilePosDelta) byteLoc;
  1739. d568 61
  1740. a628 1
  1741.     id result;
  1742. d630 7
  1743. a636 3
  1744.     if (theFile == NULL)
  1745.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  1746.                 Text: "The file wasn't even open!  How d'you expect me to move around in it?!"];
  1747. d638 52
  1748. d691 22
  1749. a712 3
  1750.         NXSeek(theFile, -byteLoc, NX_FROMCURRENT);
  1751.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  1752.                 Text: "We found what we NXsaught."];
  1753. d714 1
  1754. a714 1
  1755.     return result;
  1756. d718 16
  1757. a733 8
  1758. /**********************************************************************************
  1759.     This allocates a new string, and returns the name of the file that we have opened
  1760.     without any parent directory names or extensions.  Note that if someone somehow has
  1761.     a / in the file name itself, they're hosed here.   (and probably everywhere else as well)
  1762.     Specifically, the basename is what's in caps here: /foo/bar/BASENAME.extension
  1763.     BUG: should be returning a reply!!!
  1764. **********************************************************************************/
  1765. - (Cstring) getBasename
  1766. d735 49
  1767. a783 1
  1768.     // Determine where the last / and . are.
  1769. d785 2
  1770. a786 7
  1771.     int    lastSlash = strrpos(fileName, '/');
  1772.     int    lastDot = strrpos(fileName, '.');
  1773.     int    basenameSize, start, finish;
  1774.     Cstring    tempName;
  1775.     
  1776.     // Determine the length of the basename by figuring out where its start is
  1777.     // (either right after the /, or at the start) and the end (before . or at the end)
  1778. d788 4
  1779. a791 2
  1780.     if (lastSlash == -1)
  1781.         start = 0;
  1782. d793 1
  1783. a793 1
  1784.         start = lastSlash+1;
  1785. d795 2
  1786. a796 2
  1787.     if ((lastDot == -1) || (lastDot < lastSlash))
  1788.         finish = strlen(fileName);
  1789. d798 9
  1790. a806 1
  1791.         finish = lastDot;    // don't subtract one, becasue counting like a strlen, above.
  1792. d808 2
  1793. a809 6
  1794.     basenameSize = finish - start;
  1795.     
  1796.     // Allocate the proper space for the basename, store the text, and return it.
  1797.     tempName = (Cstring) malloc(basenameSize+1);
  1798.     strncpy(tempName, &fileName[start], basenameSize);
  1799.     tempName[basenameSize] = (char)NULL;
  1800. d814 11
  1801. a824 6
  1802. /**********************************************************************************
  1803.     This returns the current location in the file, which happens to be a direct mapping
  1804.     to the standard io routine: ftell.
  1805.     BUG: should be returning a reply?
  1806. **********************************************************************************/
  1807. - (FilePos) getCurrentPosition
  1808. d826 7
  1809. a832 3
  1810.     if (theFile == NULL)
  1811.         /* should return a better reply */
  1812.         return 0;
  1813. d834 6
  1814. a839 1
  1815.         return NXTell(theFile);
  1816. d843 13
  1817. a855 7
  1818. /**********************************************************************************
  1819.     This gets the extension of the file name, which is the portion of its name that comes
  1820.     after the last . in its name.  If there is no extension, a null string is returned.
  1821.     Specifically, the basename is what's in caps here: /foo/bar/basename.EXTENSION
  1822.     (if no extension, should return a reply with a positive error code and a null string)
  1823. **********************************************************************************/
  1824. - (Cstring) getExtension;
  1825. a856 2
  1826.     // Determine where the last / and . are. We need the / to be sure we don't get a . further
  1827.     // up in the path somewhere.
  1828. d858 10
  1829. a867 7
  1830.     int    lastSlash = strrpos(fileName, '/');
  1831.     int    lastDot = strrpos(fileName, '.');
  1832.     int    extensionSize, start;
  1833.     Cstring    tempName;
  1834.     
  1835.     // Determine the length of the extension by figuring out where its start is
  1836.     // (after the .)
  1837. d869 4
  1838. a872 2
  1839.     if ((lastDot == -1) || (lastDot < lastSlash))
  1840.         start = 0;
  1841. d874 9
  1842. a882 8
  1843.         start = lastDot+1;
  1844.     
  1845.     extensionSize = strlen(fileName) - start;
  1846.     
  1847.     // Allocate the proper space for the extension, store the text, and return it.
  1848.     tempName = (Cstring) malloc(extensionSize+1);
  1849.     strncpy(tempName, &fileName[start], extensionSize);
  1850.     tempName[extensionSize] = (char) NULL;
  1851. d887 13
  1852. a899 4
  1853. /**********************************************************************************
  1854.     This gets the name of the current file, without the pathname attached to it.
  1855. **********************************************************************************/
  1856. - (Cstring) getFilename
  1857. d901 3
  1858. a903 1
  1859.     // Determine where the last / is.
  1860. d905 6
  1861. a910 9
  1862.     int    lastSlash = strrpos(fileName, '/');
  1863.     int    nameSize, start;
  1864.     Cstring    tempName;
  1865.     
  1866.     // Determine the length of the filename by figuring out where its start is
  1867.     // (after the /)
  1868.     //    
  1869.     if (lastSlash == -1)
  1870.         start = 0;
  1871. d912 8
  1872. a919 8
  1873.         start = lastSlash+1;
  1874.     
  1875.     nameSize = strlen(fileName) - start;
  1876.     
  1877.     // Allocate the proper space for the filename, store the text, and return it.
  1878.     tempName = (Cstring) malloc(nameSize+1);
  1879.     strncpy(tempName, &fileName[start], nameSize);
  1880.     tempName[nameSize] = (char)NULL;
  1881. d924 13
  1882. a936 6
  1883. /**********************************************************************************
  1884.     this returns the path to the file that we are using without including the file name
  1885.     itself (it does include the terminal /).  Note that if there are no /'s, lastSlash gets
  1886.     set to -1, and we return a null string
  1887. **********************************************************************************/
  1888. - (Cstring) getDirectory
  1889. a937 1
  1890.     // Determine where the last / is.
  1891. d939 13
  1892. a951 5
  1893.     int    lastSlash = strrpos(fileName, '/');
  1894.     Cstring    tempName;
  1895.     
  1896.     // Allocate the proper space for the filename, store the text, and return it.
  1897.     if (lastSlash != -1)
  1898. d953 2
  1899. a954 3
  1900.         tempName = (Cstring) malloc(lastSlash+1+1); //one for 0 origin, one for null
  1901.         strncpy(tempName, fileName, lastSlash+1);
  1902.         tempName[lastSlash+1] = (char) NULL;
  1903. d957 5
  1904. a961 1
  1905.         tempName=NULL;
  1906. d966 12
  1907. a977 4
  1908. /**********************************************************************************
  1909.     this returns the full pathname of the file that we are using.
  1910. **********************************************************************************/
  1911. - (Cstring) getPathname
  1912. d979 9
  1913. a987 5
  1914.     Cstring    tempName;
  1915.  
  1916.     // Allocate the proper space for the pahtname, store the text, and return it.
  1917.     tempName = (Cstring) malloc(strlen(fileName)+1);
  1918.     strcpy(tempName, fileName);
  1919. d1000 3
  1920. d1004 2
  1921. a1005 2
  1922. //        Doc refers to exceptions being raised by NXSeek if bad things happen.  Check for them!!!!
  1923. //        Should we be checking the result of NXTell also?  (see ExceptionHandling in the doc)
  1924. d1011 2
  1925. a1012 2
  1926.     if (theFile == NULL)
  1927.         [self SetErrorCode: ERR_FILENOTOPEN
  1928. d1014 2
  1929. a1015 2
  1930.     else if (AccessType == FILE_APPEND)
  1931.         [self SetErrorCode: ERR_FILEAPPENDONLY
  1932. d1019 26
  1933. a1044 3
  1934.         NXSeek(theFile, byteLoc, NX_FROMSTART);
  1935.         [self SetErrorCode: ERR_OK AndText: "Moved OK"];
  1936.         [self StorePositiveInteger: NXTell(theFile)];
  1937. d1064 1
  1938. a1064 1
  1939. - (Byte) readByte
  1940. d1070 4
  1941. a1073 4
  1942.     if (theFile == NULL)
  1943.         [self SetErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1944.     else if ((AccessType == FILE_WRITEONLY) || (AccessType == FILE_APPEND))
  1945.         [self SetErrorCode: ERR_FILEWRITEONLY
  1946. d1077 2
  1947. a1078 2
  1948.         byteIn = NXGetc(theFile);
  1949.         [self SetErrorCode: ERR_OK AndText: "Read the byte"];
  1950. d1098 1
  1951. a1098 1
  1952. //        We don't store the EOF value yet...
  1953. d1100 1
  1954. a1100 1
  1955. - (id) read: (PositiveInteger) numBytes bytesInto: (ByteString) buffer
  1956. d1106 4
  1957. a1109 4
  1958.     if (theFile == NULL)
  1959.         [self SetErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1960.     else if ((AccessType == FILE_WRITEONLY) || (AccessType == FILE_APPEND))
  1961.         [self SetErrorCode: ERR_FILEWRITEONLY
  1962. d1113 1
  1963. a1113 1
  1964.         BytesRead = NXRead(theFile, buffer, numBytes);
  1965. d1118 1
  1966. a1118 1
  1967.             [self SetErrorCode: ERR_READINGERROR AndText: "Read the wrong number of bytes"];
  1968. d1120 2
  1969. a1121 2
  1970.             [self SetErrorCode: ERR_OK AndText: "Wrote the bytes."];
  1971.         [self StorePositiveInteger: bytesWrote];
  1972. a1136 1
  1973. //        Should we be flushing this?
  1974. d1144 4
  1975. a1147 4
  1976.     if (theFile == NULL)
  1977.         [self SetErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  1978.     else if (AccessType == FILE_READONLY)
  1979.         [self SetErrorCode: ERR_FILEREADONLY AndText: "Can not write to read-only file"];
  1980. d1150 1
  1981. a1150 1
  1982.         byteOut = NXPutc(theFile, theByte);
  1983. d1152 1
  1984. a1152 1
  1985.             [self SetErrorCode: ERR_OK AndText: "Wrote the byte"];
  1986. d1154 1
  1987. a1154 1
  1988.             [self SetErrorCode: ERR_WROTEBADCHAR AndText: "Wrote the wrong byte"];
  1989. d1171 1
  1990. a1171 2
  1991. //        error.  We always store the number of bytes we wrote.  If we fail to flush all the
  1992. //        bytes we wrote, an error is also generated (the former error takes precedence, though)
  1993. d1173 1
  1994. a1173 3
  1995. //        NXFlush doesn't seem to actually flush mapped file streams, so I don't konw what
  1996. //        error it reports.  Perhaps it should be removed entirely.  Does NXSave... provide the
  1997. //        service I'm looking for?
  1998. d1181 4
  1999. a1184 4
  2000.     if (theFile == NULL)
  2001.         [self SetErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened"];
  2002.     else if (AccessType == FILE_READONLY)
  2003.         [self SetErrorCode: ERR_FILEREADONLY AndText: "Can not write to read-only file"];
  2004. d1187 1
  2005. a1187 2
  2006.         bytesWrote = NXWrite(theFile, buffer, numBytes);
  2007.         bytesFlushed = NXFlush(theFile);
  2008. d1192 1
  2009. a1192 1
  2010.             [self SetErrorCode: ERR_WRITINGERROR
  2011. a1193 3
  2012.         else if (bytesFlushed != bytesWrote)
  2013.             [self SetErrorCode: ERR_FLUSHINGERROR
  2014.                 AndText: "Flushed the wrong number of bytes"];
  2015. d1195 1
  2016. a1195 1
  2017.             [self SetErrorCode: ERR_OK AndText: "Wrote the bytes."];
  2018. d1211 1
  2019. a1211 1
  2020. //        Probably I should be using stat instead of playing games with NXTell and NXSeek
  2021. d1218 1
  2022. a1218 1
  2023.     if (theFile == NULL)
  2024. d1220 1
  2025. a1220 1
  2026.         [self SetErrorCode: ERR_FILENOTOPEN AndText: "File was not properly opened."];
  2027. d1222 1
  2028. d1226 5
  2029. a1230 5
  2030.         currentLoc = NXTell(theFile);
  2031.         NXSeek(theFile, 0, NX_FROMEND);
  2032.         eofLoc = NXTell(theFile);
  2033.         NXSeek(theFile, currentLoc, NX_FROMSTART);
  2034.         [self SetErrorCode: ERR_OK AndText: "Obtained size of file."];
  2035. d1234 85
  2036. @
  2037.  
  2038.  
  2039. 1.4
  2040. log
  2041. @Miscelaneous revisions.  This is the last version of version 1.
  2042. @
  2043. text
  2044. @d4 2
  2045. a5 2
  2046.     This is $Revision: 1.3 $ of this file
  2047.     It was last modified by $Author: death $ on $Date: 92/03/29 12:36:14 $
  2048. d8 3
  2049. d50 2
  2050. d53 1
  2051. d395 10
  2052. a404 3
  2053. //    Routine: moveTo: 
  2054. //    Parameters: the location to move to in the file
  2055. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)
  2056. d406 1
  2057. a406 1
  2058. - (id) moveTo: (FilePos) byteLoc
  2059. d408 1
  2060. a408 1
  2061.     id result;
  2062. d411 5
  2063. a415 2
  2064.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2065.                 Text: "The file wasn't even open!  How d'you expect me to move around in it?!"];
  2066. d418 3
  2067. a420 3
  2068.         NXSeek(theFile, 0, NX_FROMSTART);
  2069.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  2070.                 Text: "We found what we NXsaught."];
  2071. d422 1
  2072. a422 1
  2073.     return result;
  2074. d427 12
  2075. a438 3
  2076. //    Routine: readByte
  2077. //    Parameters: none
  2078. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?) 
  2079. d440 1
  2080. a440 1
  2081. - (id) readByte
  2082. d442 1
  2083. a442 1
  2084.     id result;
  2085. d444 2
  2086. d447 4
  2087. a450 2
  2088.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2089.                 Text: "Unable to read from unopened file. Nuke this object, start again."];
  2090. d453 4
  2091. a456 4
  2092.         result =  [[Reply alloc] initReplyWithCode: ERR_DOBETTERERRORCHECKING
  2093.                 Text: "huh?"
  2094.                 Data: (void*) NXGetc(theFile)
  2095.                 Type: TYPE_CHAR];
  2096. d458 1
  2097. a458 2
  2098.     return result;
  2099.  
  2100. d462 13
  2101. a474 6
  2102. //    Routine: readByte:
  2103. //    Parameters: tons
  2104. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)
  2105. //    NOTE david: there IS a need for a two value Reply object...
  2106. //    WAItaminute! What does the caller care about number of bytes read...
  2107. //    We should check... if bad number, then we return an error... or...
  2108. d476 1
  2109. a476 1
  2110. - (id) read: (long int) numBytes bytesInto: (byte*) buffer retrieving: (long int*) bytesFound;
  2111. d478 4
  2112. a481 3
  2113.     id result;
  2114.     long junk2, junk3;
  2115.         
  2116. d483 4
  2117. a486 2
  2118.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2119.                 Text: "closed file.  no reading possible when the lights are out."];
  2120. d489 10
  2121. a498 5
  2122.     junk2 = NXTell(theFile);
  2123.         junk3 = NXRead(theFile, buffer, numBytes);
  2124.         *bytesFound = junk3;
  2125.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  2126.                 Text: "deludingonselferror"];
  2127. d500 1
  2128. a500 2
  2129.     return result;
  2130.  
  2131. d505 9
  2132. a513 3
  2133. //    Routine: writeByte:
  2134. //    Parameters: none
  2135. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)   flush??
  2136. d515 1
  2137. a515 1
  2138. - (id) writeByte: (byte) theByte;
  2139. d517 1
  2140. a517 2
  2141.     id result;
  2142.     char theChar;
  2143. d519 2
  2144. d522 3
  2145. a524 2
  2146.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2147.                 Text: "Unable to read from unopened file. Nuke this object, start again."];
  2148. d527 6
  2149. a532 4
  2150.         theChar = NXPutc(theFile, theByte);
  2151.         /* assure that theChar is the same as thebyte */
  2152.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  2153.                 Text: ""];
  2154. d534 1
  2155. a534 2
  2156.     return result;
  2157.  
  2158. d540 14
  2159. a553 6
  2160. //    Routine: writeByte:
  2161. //    Parameters: none
  2162. //    Bugs: header comment sucks... need better error checking. (e.g. check if at eof?)
  2163. //    NOTE david: there IS a need for a two valuereply object...
  2164. //    WAItaminute! What does the caller care about number of bytes written...
  2165. //    We should check... if bad number, then we return an error...
  2166. d555 1
  2167. a555 1
  2168. - (id) write: (long int) numBytes bytesFrom: (byte*) buffer writing: (long int*) bytesWrote;
  2169. d557 1
  2170. a557 1
  2171.     id result;
  2172. d559 2
  2173. d562 3
  2174. a564 2
  2175.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2176.                 Text: "closed file.  no writing possible."];
  2177. d567 14
  2178. a580 5
  2179.         *bytesWrote = NXWrite(theFile, buffer, numBytes);
  2180.         NXFlush(theFile);    /* make sure number bytes returned == bytesWrote) */
  2181.         /* assure that theChar is the same as thebyte */
  2182.         result =  [[Reply alloc] initErrorWithCode: ERR_PEACHY
  2183.                 Text: "deludingonselferror"];
  2184. d582 1
  2185. a582 2
  2186.     return result;
  2187.  
  2188. d587 9
  2189. a595 2
  2190. //    Routine: fileSize
  2191. //    Parameters: none
  2192. d597 1
  2193. a597 1
  2194. - (id) fileSize
  2195. d599 1
  2196. a599 3
  2197.     id result;
  2198.     FilePos    currentLoc, eofLoc;
  2199.     int junk;
  2200. d601 1
  2201. d603 4
  2202. a606 2
  2203.         result =  [[Reply alloc] initErrorWithCode: ERR_FILENOTOPEN
  2204.                 Text: "There's got to be a better way..."];
  2205. a608 1
  2206.         /* yeah.  I should probably use stat instead.  heck.  for now, though, this will suffice */
  2207. d613 2
  2208. a614 5
  2209. junk = NXTell(theFile);
  2210.         result =  [[Reply alloc] initReplyWithCode: ERR_PEACHY
  2211.                 Text: "got the size"
  2212.                 Data:  (void*) eofLoc
  2213.                 Type: TYPE_ULONG];
  2214. d616 1
  2215. a616 1
  2216.     return result;
  2217. @
  2218.  
  2219.  
  2220. 1.3
  2221. log
  2222. @Bug in the open method. If we failed, we returned OK, if we succed, we reported failure.
  2223. @
  2224. text
  2225. @d4 2
  2226. a5 2
  2227.     This is $Revision: 1.2 $ of this file
  2228.     It was last modified by $Author: death $ on $Date: 92/03/29 12:29:06 $
  2229. d8 3
  2230. d25 1
  2231. a25 1
  2232. #import <stdio.h>
  2233. d28 2
  2234. a29 1
  2235.  
  2236. d56 1
  2237. a56 1
  2238. - (id) openFile: (Cstring) workingName For: (long int) operation
  2239. d59 3
  2240. a61 1
  2241.     
  2242. d69 19
  2243. a87 2
  2244.     fileName = (Cstring) malloc(strlen(workingName) + 1);
  2245.     strcpy(fileName, workingName);
  2246. d99 9
  2247. a107 2
  2248.             theFile = NXMapFile(fileName, NX_WRITEONLY);
  2249.             break;
  2250. d109 7
  2251. a115 1
  2252.             theFile = NXMapFile(fileName, NX_READWRITE);
  2253. d131 2
  2254. a132 1
  2255.     if ((theFile == NULL) || (result == NULL))
  2256. d136 4
  2257. a139 2
  2258.         result =  [[Reply alloc]     initErrorWithCode: ERR_PEACHY
  2259.                 Text: "I found no errors (didn't look neither) so all must be OK."];
  2260. d147 1
  2261. a147 1
  2262. - (id) openFile: (Cstring) filename
  2263. d153 11
  2264. d169 8
  2265. d178 3
  2266. d182 1
  2267. a186 1
  2268.  
  2269. d266 1
  2270. d315 1
  2271. d344 1
  2272. d354 1
  2273. a354 1
  2274. - (Cstring) getPath
  2275. d366 1
  2276. d444 1
  2277. d451 3
  2278. a453 1
  2279.         *bytesFound = NXRead(theFile, buffer, numBytes);
  2280. d524 1
  2281. d536 1
  2282. @
  2283.  
  2284.  
  2285. 1.2
  2286. log
  2287. @Oops.  Managed to check in the wrong version.  this one has the code reflecting the new location of the init methods 
  2288. @
  2289. text
  2290. @d4 2
  2291. a5 2
  2292.     This is $Revision: 1.1 $ of this file
  2293.     It was last modified by $Author: death $ on $Date: 92/03/29 12:18:44 $
  2294. d8 3
  2295. d95 1
  2296. a95 1
  2297.     if ((theFile != NULL) && (result != NULL))
  2298. @
  2299.  
  2300.  
  2301. 1.1
  2302. log
  2303. @Initial revision
  2304. @
  2305. text
  2306. @d4 2
  2307. a5 2
  2308.     This is $Revision:$ of this file
  2309.     It was last modified by $Author: $ on $Date: $
  2310. d7 4
  2311. a10 1
  2312.  * $Log:$
  2313. d53 1
  2314. a53 1
  2315.     [super initialize];
  2316. d84 1
  2317. a84 1
  2318.             result =  [Reply     initErrorWithCode: ERR_BADACCESS
  2319. d93 1
  2320. a93 1
  2321.             result =  [Reply     initErrorWithCode: ERR_CANTOPEN
  2322. d96 1
  2323. a96 1
  2324.         result =  [Reply     initErrorWithCode: ERR_PEACHY
  2325. d133 1
  2326. a133 1
  2327.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2328. d138 1
  2329. a138 1
  2330.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2331. d156 1
  2332. a156 1
  2333.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2334. d161 1
  2335. a161 1
  2336.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2337. d330 1
  2338. a330 1
  2339.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2340. d335 1
  2341. a335 1
  2342.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2343. d352 1
  2344. a352 1
  2345.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2346. d356 1
  2347. a356 1
  2348.         result =  [Reply initReplyWithCode: ERR_DOBETTERERRORCHECKING
  2349. d378 1
  2350. a378 1
  2351.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2352. d383 1
  2353. a383 1
  2354.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2355. d402 1
  2356. a402 1
  2357.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2358. d408 1
  2359. a408 1
  2360.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2361. d421 1
  2362. a421 1
  2363. //    NOTE david: there IS a need for a two value Reply object...
  2364. d430 1
  2365. a430 1
  2366.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2367. d437 1
  2368. a437 1
  2369.         result =  [Reply initErrorWithCode: ERR_PEACHY
  2370. d455 1
  2371. a455 1
  2372.         result =  [Reply initErrorWithCode: ERR_FILENOTOPEN
  2373. d464 1
  2374. a464 1
  2375.         result =  [Reply initReplyWithCode: ERR_PEACHY
  2376. @
  2377.